<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<h2>一、call,apply,bind的相同点：</h2>

<ul>
    <li>都是改变this指向的</li>
    <li>第一个参数都是this要指向的对象</li>
    <li>都可以利用后续参数传参</li>
</ul>
<h2>二、call,apply,bind的区别：</h2>

<ul>
    <li>三者都可以改变函数的this对象指向。</li>
    <li>三者第一个参数都是this要指向的对象，如果如果没有这个参数或参数为undefined或null，则默认指向全局window。</li>
    <li>call和bind的参数是依次传参，一一对应的,而bind可以分为多次传入</li>
    <li>但apply只有两个参数，第二个参数为数组</li>
    <li>call和apply都是对函数进行直接调用，而bind方法返回的仍是一个函数</li>
    <li>bind 是返回绑定this之后的函数，便于稍后调用；apply 、call 则是立即执行 。</li>
</ul>

<pre>
 // 例如一：
    var a = {
        name: '石头',
        age: '20',
        sex: '女',
        hobby: '撸代码',
        say: function (sex, hobby) {
            console.log(this.name, this.age, sex, hobby)
        }
    }
    var b = {
        name: '狗蛋',
        age: '21',
    }
    a.say.call(b, 'call', '学习'); //结果为："狗蛋","23","call","学习"
    a.say.apply(b, ['apply', '学习']) //结果为："狗蛋","23","apply","学习"
    // bind可以向cally一样传参：
    a.say.bind(b, 'bind1', '学习')(); //结果为："狗蛋","23","bind1","学习"
    // 但由于bind返回的仍然是一个函数，所以我们还可以在调用的时候再进行传参。
    a.say.bind(b)('bind2', '学习'); //结果为："狗蛋","23","bind2","学习"

 // 例如二：
    var aa = 1,bb=2;
    function obj(num1,num2){
        return this.aa+this.bb + num1 + num2
    }
    var cc={aa:3,bb:4}
    console.log(obj.call(cc,1,2))   //10
    console.log(obj.apply(cc,[1,2])) //10
    console.log(obj.bind(cc,1,2)()) //10

 // 例如三：
    var name="铁蛋";
    let obj1={
        name:"金蛋",
        say:function () {
            console.log(this.name);
        }
    };
    obj1.say(); //金蛋，this指向obj对象
    setTimeout(obj1.say,0); //铁蛋，this指向window对象

    // 可以看出，正常情况下 say 方法中的 this 是指向调用它的 obj 对象的，
    // 而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中)，
    // 这是因为 say 方法在定时器中是作为回调函数来执行的，
    // 因此回到主栈执行时是在全局执行上下文的环境中执行的，
    // 但我们需要的是 say 方法中 this 指向obj对象，因此我们需要修改 this 的指向
    
    
    
    // 改变this指向
    var name2="铁蛋";
    var obj2={
        name2:"金蛋",
        say2:function(sex,flag){
            console.log(this.name2+"是"+sex+flag);
        }
    };
    var say2=obj2.say2;
    setTimeout(function(){
        say2.apply(obj2,["男人","apply"]);
        say2.call(obj2,"男人","call");
        say2.bind(obj2,"男人","bind")();
    } ,0); // this改变指向了obj2
    say2("男人","window")  //this指向window，说明apply只是临时改变一次this指向
</pre>
<script>
    // 例如1：
    var a = {
        name: '石头',
        age: '20',
        sex: '女',
        hobby: '撸代码',
        say: function (sex, hobby) {
            console.log(this.name, this.age, sex, hobby)
        }
    }
    var b = {
        name: '狗蛋',
        age: '21',
    }
  
    a.say.call(b, 'call', '学习'); //结果为："狗蛋","23","call","学习"
    a.say.apply(b, ['apply', '学习']) //结果为："狗蛋","23","apply","学习"
    // bind可以向cally一样传参：
    // 例如:
    a.say.bind(b, 'bind1', '学习')(); //结果为："狗蛋","23","bind1","学习"
    // 但由于bind返回的仍然是一个函数，所以我们还可以在调用的时候再进行传参。
    // 例如：
    a.say.bind(b)('bind2', '学习'); //结果为："狗蛋","23","bind2","学习"


    // 例如2：
    var aa = 1,bb=2;
    function obj(num1,num2){
        return this.aa+this.bb + num1 + num2
    }
    var cc={aa:3,bb:4}
    console.log(obj.call(cc,1,2))   //10
    console.log(obj.apply(cc,[1,2])) //10
    console.log(obj.bind(cc,1,2)()) //10

    // 例如3：
    var name1="铁蛋";
    let obj1={
        name1:"金蛋",
        say:function () {
            console.log(this.name1);
        }
    };
    obj1.say(); //金蛋，this指向obj对象
    setTimeout(obj1.say,0); //铁蛋，this指向window对象

    // 可以看出，正常情况下 say 方法中的 this 是指向调用它的 obj 对象的，
    // 而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中)，
    // 这是因为 say 方法在定时器中是作为回调函数来执行的，
    // 因此回到主栈执行时是在全局执行上下文的环境中执行的，
    // 但我们需要的是 say 方法中 this 指向obj对象，因此我们需要修改 this 的指向
    
    
    // 改变this指向
    var name2="铁蛋";
    var obj2={
        name2:"金蛋",
        say2:function(sex,flag){
            console.log(this.name2+"是"+sex+flag);
        }
    };
    var say2=obj2.say2;
    setTimeout(function(){
        say2.apply(obj2,["男人","apply"]);
        say2.call(obj2,"男人","call");
        say2.bind(obj2,"男人","bind")();
    } ,0); // this改变指向了obj2
    say2("男人","window")  //this指向window，说明apply只是临时改变一次this指向
</script>


</body>
</html>
